package clean_handler

import (
	"file-cleaner/internal/file_cleaner/cleaner"
	"file-cleaner/internal/file_cleaner/file_info"
	"sync"
)

type handleInfo struct {
	//timestamp time.Time
	isSucceed bool
	taskInfo  *cleaner.CleanTaskInfo
}

func newHandleInfo(info *cleaner.CleanTaskInfo, isSucceed bool) *handleInfo {
	return &handleInfo{
		//timestamp: time.Now(),
		isSucceed: isSucceed,
		taskInfo:  info,
	}
}

type CleanTaskInfoCache struct {
	cache []*handleInfo
	*sync.RWMutex
}

func NewCleanTaskInfoCache() *CleanTaskInfoCache {
	return &CleanTaskInfoCache{
		cache:   make([]*handleInfo, 0),
		RWMutex: new(sync.RWMutex),
	}
}

func (cc *CleanTaskInfoCache) add(info *handleInfo) {
	cc.Lock()
	defer cc.Unlock()
	cc.cache = append(cc.cache, info)
	//sort.Slice(cc.cache, func(i, j int) bool {
	//	return cc.cache[i].timestamp.Before(cc.cache[j].timestamp)
	//})
}

func (cc *CleanTaskInfoCache) getCache() []*handleInfo {
	cc.RLock()
	defer cc.RUnlock()
	return cc.cache
}

type CleanTaskInfoCollector struct {
	cache *CleanTaskInfoCache
}

func NewCleanTaskInfoCollector(cache *CleanTaskInfoCache) *CleanTaskInfoCollector {
	return &CleanTaskInfoCollector{cache: cache}
}

func (ccl *CleanTaskInfoCollector) Record(taskInfo *cleaner.CleanTaskInfo, isSucceed bool) {
	ccl.cache.add(newHandleInfo(taskInfo, isSucceed))
}

func GenCleanTaskInfoCollectorAndCache() (*CleanTaskInfoCollector, *CleanTaskInfoCache) {
	cache := NewCleanTaskInfoCache()
	return NewCleanTaskInfoCollector(cache), cache
}

type CleanTaskStatisticsResult struct {
	TotalFilesCount          int
	NeedHandledFilesCount    int
	SucceedHandledFilesCount int
	TotalFilesSize           int64
	NeedHandledFilesSize     int64
	SucceedHandledFilesSize  int64
}

type Aggregator struct {
}

func NewAggregator() *Aggregator {
	return new(Aggregator)
}

func (a *Aggregator) Aggregate(cache *CleanTaskInfoCache) CleanTaskStatisticsResult {
	return a.doAggregate(cache.getCache())
}

func (a *Aggregator) doAggregate(cache []*handleInfo) CleanTaskStatisticsResult {
	result := CleanTaskStatisticsResult{}
	inResult := make(map[string]bool)
	for _, info := range cache {

		// aggregate target file info to total records
		if !inResult[info.taskInfo.TargetFileInfo().Path()] {
			inResult[info.taskInfo.TargetFileInfo().Path()] = true
			result.TotalFilesCount++
			result.TotalFilesSize += info.taskInfo.TargetFileInfo().Size()
		}
		if !info.taskInfo.IsSamePath() {
			result.TotalFilesCount++
			result.TotalFilesSize += info.taskInfo.SourceFileInfo().Size()
		} else {
			if info.taskInfo.SourceFileInfo().GetTag() != file_info.OnlyDelete {
				continue
			}
		}

		// skip aggregate for task source file info, whose tag is `SkipOperation`
		if info.taskInfo.SourceFileInfo().GetTag() == file_info.SkipOperation {
			continue
		}

		// aggregate task source file info
		result.NeedHandledFilesCount++
		result.NeedHandledFilesSize += info.taskInfo.SourceFileInfo().Size()

		// aggregate succeed task source file info
		if info.isSucceed {
			result.SucceedHandledFilesCount++
			result.SucceedHandledFilesSize += info.taskInfo.SourceFileInfo().Size()
		}

	}
	return result
}
